﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using jp110311.StorageModels;
using MvcWebRole1.Models;

namespace MvcWebRole1.Controllers
{
    public class MessagingController : Controller
    {
        private const int PageSize=15;
        //
        // GET: /Messaging/Index/{mode}/{page}

        [Authorize]
        public ActionResult Index( string mode, int page )
        {
            UserMessagingIndexModel model = FillIndexModel(mode, page);
            return View(model);
        }

        private UserMessagingIndexModel FillIndexModel(string mode, int page)
        {
            var model = new UserMessagingIndexModel
                        {
                            Mode = mode,
                            CurrentPage = page
                        };
            if (mode == "Unread")
            {
                model.TotalMessages = UserMessagingService.CountUnreadMessage(User.Identity.Name);
                model.Messages = UserMessagingService.ListUnreadMessage(User.Identity.Name, (page-1)*PageSize, PageSize);
            }
            if (mode == "Archive")
            {
                model.TotalMessages = UserMessagingService.CountMessage(User.Identity.Name);
                model.Messages = UserMessagingService.ListMessage(User.Identity.Name, (page - 1)*PageSize, PageSize);
            }
            if (mode == "Importance")
            {
                model.TotalMessages = UserMessagingService.CountImportanceMessage(User.Identity.Name);
                model.Messages = UserMessagingService.ListImportanceMessage(User.Identity.Name, (page - 1)*PageSize,
                                                                            PageSize);
            }
            model.TotalPages = (model.TotalMessages/PageSize) + 1;
            return model;
        }

        [HttpPost]
        [Authorize]
        public ActionResult Index(string mode,int page, UserMessagingIndexModel model )
        {
            if (Request.Form.AllKeys.Contains("mark"))
            {
                var form = new Dictionary<string, object>();
                Request.Form.CopyTo(form);

                foreach (var kvp in form.Where(kvp => kvp.Key.StartsWith("chk_")))
                {
                    string id = kvp.Key.Substring(4);
                    UserMessagingService.MarkMessageImportance(User.Identity.Name, id);
                }
            }
            model = FillIndexModel(mode, page);
            return View(model);
        }

        // GET: /Send
        [Authorize]
        public ActionResult Send()
        {
            var model = new UserMessagingSendModel();
            RefreshSendModel(model);
            return View(model);
        }

        private void RefreshSendModel(UserMessagingSendModel model)
        {
            IEnumerable<UserAddressBookEntity> addressList;
            if (string.IsNullOrEmpty(model.Tag))
            {
                model.AddressBookMaxPage =
                    (UserMessagingService.CountAddressBookItems(User.Identity.Name)/PageSize) + 1;
                addressList = UserMessagingService.GetAddressBookItems(
                    User.Identity.Name, (model.AddressBookPageNum - 1)*PageSize, PageSize);

            }
            else
            {
                model.AddressBookMaxPage =
                    (UserMessagingService.CountAddressBookItemsByTag(User.Identity.Name, model.Tag)/PageSize) + 1;
                addressList =
                    UserMessagingService.GetAddressBookItemsByTag(User.Identity.Name,model.Tag,
                                                                  (model.AddressBookPageNum - 1)*PageSize, PageSize);
            }
            foreach (var userAddressBookEntity in addressList)
            {
                model.AddressList.Add(
                    new Address
                    {
                        Name = userAddressBookEntity.BookedUser,
                        Selected = false
                    }
                    );
            }

            model.AddressBookTagList =
                UserMessagingService
                    .GetAddressBookTags(User.Identity.Name)
                    .Select( t=> new AddressBookTag 
                    { Name = t.TagName, Count = t.UserList.Split(';').Length });
        }

        [Authorize]
        [HttpPost]
        public ActionResult Send( UserMessagingSendModel model )
        {
            if (Request.Form.AllKeys.Contains("addRecipient"))
            {
                var form = new Dictionary<string, object>();
                Request.Form.CopyTo(form);
                List<string> recipients = model.Recipents != null 
                    ? model.Recipents.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries).ToList()
                    : new List<string>();

                foreach (var kvp in form.Where( kvp=>kvp.Key.StartsWith("adr_"))  )
                {
                    if (GetCheckBoxValue(kvp.Value)) continue;
                    string addr = kvp.Key.Substring(4);
                    if( recipients.Contains(addr) ) continue;
                    recipients.Add(addr);
                }
                model.Recipents = string.Join(";", recipients);
            }
            else if (Request.Form.AllKeys.Contains("delRecipient"))
            {
                var form = new Dictionary<string, object>();
                Request.Form.CopyTo(form);
                List<string> recipients = model.Recipents != null
                    ? model.Recipents.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries).ToList()
                    : new List<string>();

                foreach (var kvp in form.Where(kvp => kvp.Key.StartsWith("del_")))
                {
                    if (GetCheckBoxValue(kvp.Value)) continue;
                    string addr = kvp.Key.Substring(4);
                    if (!recipients.Contains(addr)) continue;
                    recipients.Remove(addr);
                }
                model.Recipents = string.Join(";", recipients);
                
            }
            else if (Request.Form.AllKeys.Contains("prevPageAddr"))
            {
                model.AddressBookPageNum--;
            }
            else if (Request.Form.AllKeys.Contains("nextPageAddr"))
            {
                model.AddressBookPageNum++;
            }
            else if (Request.Form.AllKeys.Contains("send"))
            {
                if (ModelState.IsValid)
                {
                    string validationKey = GetValidationKey(model);
                    model.ValidationKey = validationKey;
                    return View("SendConfirm", model);
                }
            }
            else if (Request.Form.AllKeys.Contains("sendConfirm"))
            {
                if (ModelState.IsValid)
                {
                    string validationKey = GetValidationKey(model);
                    if (model.ValidationKey == validationKey)
                    {
                        UserMessagingService.SendMessage(
                            User.Identity.Name,
                            DateTime.UtcNow,
                            model.Recipents,
                            model.Title,
                            model.Content
                            );
                        model.Message = "送信されました";
                        return View("SendSuccess", model);
                    }
                    model.Message = "送信データを検証できませんでした。";
                }
            }
            RefreshSendModel(model);
            return View(model);
        }

        private static string GetValidationKey(UserMessagingSendModel model)
        {
            var sha1 = SHA1.Create();
            var sb = new StringBuilder();
            var machineKey =
                (MachineKeySection) WebConfigurationManager.GetSection("system.web/machineKey");
            sb.Append(machineKey.ValidationKey);
            sb.Append(model.Title);
            sb.Append(model.Content);
            sb.Append(model.Recipents);
            var buffer= Encoding.Unicode.GetBytes(sb.ToString());
            var hash = sha1.ComputeHash(buffer);
            return Convert.ToBase64String(hash);
        }

        private static bool GetCheckBoxValue(object value  )
        {
            var s = (string)value;
            var values = s.Split(',');
            return !bool.Parse(values[0]);
        }


        [Authorize]
        public ActionResult AddrBook( int page )
        {
            var model = new AddressBookIndexModel
                        {
                            CurrentPage = page,
                            TotalCount = UserMessagingService.CountAddressBookItems(User.Identity.Name),
                            AddressList =
                                UserMessagingService.GetAddressBookItems(User.Identity.Name, (page - 1)*PageSize,
                                                                         PageSize)
                        };
            model.MaxPage = (model.TotalCount/PageSize) + 1;
            return View(model);
        }

        [Authorize]
        public ActionResult AddAddr()
        {
            var model = new UserListQueryModel();
            return View(model);
        }

        [Authorize]
        [HttpPost]
        public ActionResult AddAddr( UserListQueryModel model )
        {
            if (ModelState.IsValid)
            {
                var entity = UserEntityService.FindUser( 
                    model.ZipCode, 
                    model.FamilyName, 
                    model.GivenName, 
                    model.BirthDate);
                if (entity == null)
                {
                    model.QueryResult = "該当するユーザーが存在しないか複数該当します。条件を設定してください。";
                    return View(model);
                }
                string bookUsername = model.ZipCode + "@" + entity.NickName;
                UserMessagingService.AddressBookAdd( User.Identity.Name, new[]{bookUsername}, model.Memo, new[]{ model.Tag} );
                model.Clear();
                model.QueryResult = bookUsername + "がアドレス帳に追加されました。";
            }
            return View(model);
        }

        [Authorize]
        public ActionResult DeleteAddr(string bookedUser )
        {
            UserMessagingService.AddressBookRemoveEntry(User.Identity.Name, bookedUser);
            return RedirectToAction("AddrBook");
        }

        [Authorize]
        public ActionResult TagAddr( string bookedUser )
        {
            var model = new TagAddressBookUserModel
                        {
                            BookedUser = bookedUser
                        };
            return View(model);
        }

        [Authorize]
        [HttpPost]
        public ActionResult TagAddr(TagAddressBookUserModel model)
        {
            if (ModelState.IsValid)
            {
                string[] tag = model.TagList.Split(new[]{ Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
                UserMessagingService.AddressBookAdd( User.Identity.Name, new[]{ model.BookedUser}, "", tag);
                return RedirectToAction("AddrBook");
            }
            return RedirectToAction("AddrBook");
        }



        [Authorize]
        public ActionResult UnTagAddr(string bookedUser, string tag)
        {
            if (ModelState.IsValid)
            {
                UserMessagingService.AddressBookRemoveTag(User.Identity.Name, new[]{bookedUser}, tag);
            }
            return RedirectToAction("AddrBook");
        }

        [Authorize]
        public ActionResult Detail(string mode, string id)
        {
            var model = new ViewMessageModel();
            model.Mode = mode;
            if (id != null)
            {
                model.Message = UserMessagingService.GetMessage(User.Identity.Name, id);
            }
            return View(model);
        }

        [Authorize]
        public ActionResult Unmark( string mode, string id)
        {
            UserMessagingService.UnmarkMessageImportance( User.Identity.Name, id);
            return RedirectToAction("Detail", new { mode, id});
        }

        [Authorize]
        public ActionResult Next(string mode, string id, bool markRead = false, bool markImportance = false)
        {
            string nextId;
            switch (mode)
            {
                case "Archive":
                    nextId = UserMessagingService.GetNextMessageId(User.Identity.Name, id);
                    break;
                case "Unread":
                    nextId = UserMessagingService.GetNextUnreadMessageId(User.Identity.Name, id);
                    break;
                case "Importance":
                    nextId = UserMessagingService.GetNextImportanceMessageId(User.Identity.Name, id);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("mode");
            }
            if (markRead)
            {
                UserMessagingService.MarkMessageToRead(User.Identity.Name, id);
            }
            if (markImportance)
            {
                UserMessagingService.MarkMessageImportance(User.Identity.Name, id);
            }
            return RedirectToAction("Detail", new { mode, id = nextId });
        }

        [Authorize]
        public ActionResult Prev(string mode, string id, bool markRead = false, bool markImportance = false)
        {
            string nextId;
            switch (mode)
            {
                case "Archive":
                    nextId = UserMessagingService.GetPrevMessageId(User.Identity.Name, id);
                    break;
                case "Unread":
                    nextId = UserMessagingService.GetPrevUnreadMessageId(User.Identity.Name, id);
                    break;
                case "Importance":
                    nextId = UserMessagingService.GetPrevImportanceMessageId(User.Identity.Name, id);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("mode");
            }
            if (markRead)
            {
                UserMessagingService.MarkMessageToRead(User.Identity.Name, id);
            }
            if (markImportance)
            {
                UserMessagingService.MarkMessageImportance(User.Identity.Name, id);
            }
            return RedirectToAction("Detail", new { mode, id = nextId });
        }
    }
}
